<html>
<head>
<meta charset="UTF-8"> 
<!-- This is a test of libopenjph javascript -->
<script type="text/javascript" src="libopenjph.js"></script>
</head>
<body>
<h1>HTJ2K decoding in a browser</h1>
<pre style="font-size:16px">
Decoding the full resolution image.
</pre>
<canvas id="mycanvas" width="512" height="512"></canvas>
<br>
<pre id="time" style="font-size: 16px">Decode time: </pre>

<h1>HTJ2K progressive decoding to the actual image resolution</h1>
<pre style="font-size:16px">
This example shows that one source image can be used for multiple reconstructed resolutions.
The client/browser can decide, depending on the rendering resolution, the number of bytes to load and decode for a given image.

Note: Below each image, we display the number of decoded bytes
</pre>
<table>
  <tr>
    <td></td>
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c5' width=48px"> </canvas></td>
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c4' width=48px"> </canvas></td>
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c3' width=64px"> </canvas></td>
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c2' width=128px"></canvas></td>
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c1' width=256px"></canvas></td>    
    <td style="text-align:center; vertical-align:bottom; height:512px"><canvas id='r1c0' width=512px"></canvas></td>    
  </tr>                                                       
  <tr>
    <td style="text-align:center; width:64px"> <pre>Decoded<br/>Bytes<br><pre>Time</pre></br></pre></td>
    <td style="text-align:center; width:48px"> <pre>826<br/>bytes<br><pre id='t1c5'> ms</pre></br></pre></td>
    <td style="text-align:center; width:48px"> <pre>2312<br/>bytes<br><pre id='t1c4'> ms</pre></br></pre></td>
    <td style="text-align:center; width:64px"> <pre>5977<br/>bytes<br><pre id='t1c3'> ms</pre></br></pre></td>
    <td style="text-align:center; width:128px"><pre>13022<br/>bytes<br><pre id='t1c2'> ms</pre></br></pre></td>
    <td style="text-align:center; width:256px"><pre>22005<br/>bytes<br><pre id='t1c1'> ms</pre></br></pre></td>
    <td style="text-align:center; width:512px"><pre>32553<br/>bytes<br><pre id='t1c0'> ms</pre></br></pre></td>
  </tr>
</table>

<h1>HTJ2K progressive decoding to full resolution (downloaded once, decoded many ways)</h1>
<pre style="font-size:16px">
This example shows the progressive decoding of JPEG2000. 
Image quality improves as more data arrives. This is better than waiting for the whole image to arrive before decoding it.

Note: Below each image, we display the number of decoded bytes and PSNR.
</pre>
<table>
  <tr>
    <td><canvas id='r2c5' width="512px" height="512px"></canvas></td>
    <td><canvas id='r2c4' width="512px" height="512px"></canvas></td>
  </tr>
  <tr>
    <td><pre style="text-align:center">Decoded Bytes: 826 bytes</pre></td>
    <td><pre style="text-align:center">Decoded Bytes: 2312 bytes</pre></td>
  </tr>
  <tr>
    <td><pre style="text-align:center">PSNR: 16.96 dB</pre></td>
    <td><pre style="text-align:center">PSNR: 18.25 dB</pre></td>
  </tr>
  <tr>
    <td><pre id='t2c5' style="text-align:center">Decode Time: </pre></td>
    <td><pre id='t2c4' style="text-align:center">Decode Time: </pre></td>
  </tr>
  <tr>
    <td><canvas id='r2c3' width="512px" height="512px"></canvas></td>
    <td><canvas id='r2c2' width="512px" height="512px"></canvas></td>
  </tr>
  <tr>
    <td><pre style="text-align:center">Decoded Bytes: 5977 bytes</pre></td>
    <td><pre style="text-align:center">Decoded Bytes: 13022 bytes</pre></td>
  </tr>
  <tr>
    <td><pre style="text-align:center">PSNR: 21.21 dB</pre></td>
    <td><pre style="text-align:center">PSNR: 25.46 dB</pre></td>
  </tr>
  <tr>
    <td><pre id='t2c3' style="text-align:center">Decode Time: </pre></td>
    <td><pre id='t2c2' style="text-align:center">Decode Time: </pre></td>
  </tr>
  <tr>
    <td><canvas id='r2c1' width="512px" height="512px"></canvas></td>    
    <td><canvas id='r2c0' width="512px" height="512px"></canvas></td>    
  </tr>
  <tr>
    <td><pre style="text-align:center">Decoded Bytes: 22005 bytes</pre></td>
    <td><pre style="text-align:center">Decoded Bytes: 32553 bytes</pre></td>
  </tr>
  <tr>
    <td><pre style="text-align:center">PSNR: 30.82 dB</pre></td>
    <td><pre style="text-align:center">PSNR: 37.13 dB</pre></td>
  </tr>
  <tr>
    <td><pre id='t2c1' style="text-align:center">Decode Time: </pre></td>
    <td><pre id='t2c0' style="text-align:center">Decode Time: </pre></td>
  </tr>
</table>
<script>

     Module.onRuntimeInitialized = async _ => {
        create_j2c_data = Module.cwrap('create_j2c_data', 'number');
        init_j2c_data = Module.cwrap('init_j2c_data', 'void', ['number', 'number', 'number']);
        get_j2c_width = Module.cwrap('get_j2c_width', 'number', ['number', 'number']);
        get_j2c_height = Module.cwrap('get_j2c_height', 'number', ['number', 'number']);
        get_j2c_bit_depth = Module.cwrap('get_j2c_bit_depth', 'number', ['number', 'number']);
        get_j2c_is_signed = Module.cwrap('get_j2c_is_signed', 'number', ['number', 'number']);
        get_j2c_num_components = Module.cwrap('get_j2c_num_components', 'number', ['number']);
        get_j2c_downsampling_x = Module.cwrap('get_j2c_downsampling_x', 'number', ['number', 'number']);
        get_j2c_downsampling_y = Module.cwrap('get_j2c_downsampling_y', 'number', ['number', 'number']);
        parse_j2c_data = Module.cwrap('parse_j2c_data', 'void', ['number']);
        restrict_input_resolution = Module.cwrap('restrict_input_resolution', 'void', ['number', 'number', 'number']);
        enable_resilience = Module.cwrap('enable_resilience', 'void', ['number']);
        pull_j2c_line = Module.cwrap('pull_j2c_line', 'number', ['number']);
        release_j2c_data = Module.cwrap('release_j2c_data', 'void', ['number']);

        function display_image(Module, data, canvas_name, skip_res_for_data, skip_res_for_recon, txt_ele_name, pre_text)
        {
          var t0 = performance.now();
        
          j2c = create_j2c_data();
          const array = new Uint8Array(data, 0, data.byteLength);
          
          var buffer = Module._malloc(array.length);
          writeArrayToMemory(array, buffer);
          enable_resilience(j2c);
          init_j2c_data(j2c, buffer, array.length);
          restrict_input_resolution(j2c, skip_res_for_data, skip_res_for_recon);
          var width = get_j2c_width(j2c, 0) | 0;          //component 0
          var height = get_j2c_height(j2c, 0) | 0;        //component 0
          var num_comps = get_j2c_num_components(j2c) | 0;
          var bit_depth = get_j2c_bit_depth(j2c, 0) | 0;  //component 0
          var is_signed = get_j2c_is_signed(j2c, 0) == 1; //component 0
          parse_j2c_data(j2c);
          
          var canvas = document.getElementById(canvas_name);
          canvas.width = width;
          canvas.height = height;
          var ctx = canvas.getContext("2d");
          var cimg = ctx.createImageData(width, height);

          var shift = (bit_depth >= 8 ? bit_depth - 8 : 0) | 0;
          var half = (bit_depth > 8 ? (1<<(shift-1)) : 0) | 0;
          var heap = Module["HEAP32"];
          var dst = cimg.data;
          if (num_comps == 1)
          {
            for (var y = 0|0; y < height; y = y + 1|0)
            {
              //src is an address in memory, but since we are 
              // dealing with integers (i.e, each entry is 4 bytes 
              // away from the previous sample, we need to divide by 4
              var src = pull_j2c_line(j2c) >> 2; 
              var didx = y * width * 4;
              for (var x = 0|0; x < width; x = x + 1|0)
              {
                var val = (heap[src + x] + half) >> shift;
                dst[didx + x * 4    ] = val;
                dst[didx + x * 4 + 1] = val;
                dst[didx + x * 4 + 2] = val;
                dst[didx + x * 4 + 3] = 255;
              }
            }
          }
          else if (num_comps == 3)
          {
            for (var y = 0|0; y < height; y = y + 1|0)
            {
              for (var c = 0|0; c < num_comps; c = c + 1|0)
              {
                //src is an address in memory, but since we are 
                // dealing with integers (i.e, each entry is 4 bytes 
                // away from the previous sample, we need to divide by 4
                var src = pull_j2c_line(j2c) >> 2; 
                var didx = y * width * 4 + c;
                for (var x = 0|0; x < width; x = x + 1|0)
                {
                  var val = (heap[src + x] + half) >> shift;
                  dst[didx + x * 4] = val;
                }
              }
              var didx = y * width * 4 + 3;
              for (var x = 0|0; x < width; x = x + 1|0)
                dst[didx + x * 4] = 255;
            }
          }
          else
            console.log('Unsupported number of components');
          
          release_j2c_data(j2c);

          ctx.putImageData(cimg, 0, 0);
          Module._free(buffer);  

          var t1 = performance.now();
          document.getElementById(txt_ele_name).innerText = pre_text + (t1 - t0).toFixed(2) + " ms";
        }

        var request = new XMLHttpRequest;
        request.open("GET", "test.j2c" , true);
        request.responseType = "arraybuffer";
        request.onload = function (event) {
            if (request.status == 200)
            {
                display_image(Module, this.response, 'mycanvas', 0, 0, 'time', 'Decode Time: ' );

                for (var i = 0; i <= 5; ++i)
                  display_image(Module, this.response, 'r1c' + i, i, i, 't1c' + i, '');

                for (var i = 0; i <= 5; ++i)
                  display_image(Module, this.response, 'r2c' + i, i, 0, 't2c' + i, 'Decode Time: ');
            }
        };
        request.send(null);
     }
</script>
</body>
</html>
